#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Predesys Server - User Interface - Services management 
@version: 0.2.5
@license: GPL 3.0 (see "license" file)
@author: Jose A. Jimenez
@contact: jajimc@gmail.com"""

import sys
sys.dont_write_bytecode = True
import os
import os.path
DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.path.join(DIR, "../core"))
import getpass
import security
import exceptions
import usage
import tools
import services
    
def manageArgs(argc, argv):
    """Manages command line input.
    @param argc: Command line argument count
    @type argc: C{int}
    @param argv: Command line input data
    @type argv: C{list}"""
    if argc == 3 and sys.argv[2] == "list":
        print_service_list()
    elif argc == 7 and sys.argv[2] == "list" and sys.argv[3] == "-e" and sys.argv[5] == "-tid":
        print_service_list_by_type_enabled(argv)
    elif argc == 5 and sys.argv[2] == "list" and sys.argv[3] == "-tid":
        print_service_list_by_type(argv)
    elif argc == 4 and sys.argv[2] == "data":
        print_service_data(sys.argv[3])
    elif argc == 3 and sys.argv[2] == "add":
        add_service_interactively()
    elif argc > 3 and sys.argv[2] == "add":
         add_service(sys.argv)
    elif argc == 3 and sys.argv[2] == "mod":
        modify_service_interactively()
    elif argc > 3 and sys.argv[2] == "mod":
        modify_service(sys.argv)
    elif argc == 7 and sys.argv[2] == "auth":
        authenticate_service(sys.argv)
    elif argc == 7 and sys.argv[2] == "enable":
        enable_service(sys.argv)
    elif argc == 4 and sys.argv[2] == "del":
        delete_service(sys.argv[3], True)
    elif argc == 5 and sys.argv[2] == "del" and sys.argv[3] == "-f":
        delete_service(sys.argv[4], False)
    elif ((argc == 11 and "-args" in sys.argv) or (argc == 9 and (not "-args" in sys.argv))) and sys.argv[2] == "run":
        run_callable_auth_service(sys.argv, True)
    elif ((argc == 9 and "-args" in sys.argv) or (argc == 7 and (not "-args" in sys.argv))) and sys.argv[2] == "run":
        run_callable_auth_service(sys.argv, False)
    elif (argc >= 5) and sys.argv[2] == "run":
        run_callable_service(sys.argv)
    elif (argc >= 5) and sys.argv[2] == "runauto":
        run_automatic_service(sys.argv)
    else:
        print usage.get_usage()
        
def print_service_list():
    """Prints the ID of every service."""
    serviceList = services.get_services()
    for serviceId in serviceList:
        print serviceId

def print_service_list_by_type(argv):
    """Prints the ID of every service of a given type.
    @param argv: Command line input data
    @type argv: C{list}"""
    serviceTypeId = tools.get_parameter_value(argv, "tid")
    if serviceTypeId == None:
        raise exceptions.Exception("Service type ID attribute not valid or not specified")
        
    serviceList = services.get_services_by_type(serviceTypeId)
    for serviceId in serviceList:
        print serviceId

def print_service_list_by_type_enabled(argv):
    """Prints the ID of every enabled service of a given type.
    @param argv: Command line input data
    @type argv: C{list}"""
    enabled = tools.get_parameter_value(argv, "e")
    if enabled == None or (enabled != "0" and enabled != "1"):
        raise exceptions.Exception("Enabled attribute not valid or not specified")
    enabled = (enabled == "1")

    serviceTypeId = tools.get_parameter_value(argv, "tid")
    if serviceTypeId == None:
        raise exceptions.Exception("Service type ID attribute not valid or not specified")

    if enabled: serviceList = services.get_enabled_services_by_type(serviceTypeId)
    else: serviceList = services.get_disabled_services_by_type(serviceTypeId)
    
    for serviceId in serviceList:
        print serviceId
        
def print_service_data(id):
    """Prints all fields of a service.
    @param id: Service ID
    @type id: C{str}"""       
    serviceData = services.get_service_data(id)
    
    print "ID: %s" % serviceData.get_id()
            
    version = serviceData.get_version()
    if version == None or version == "": version = "<None>"
    print "VERSION: %s" % version
    
    serviceType = serviceData.get_type()
    if serviceType != None: serviceTypeId = serviceType.get_id()
    else: serviceTypeId = "<None>"
    print "TYPE: %s" % serviceTypeId
    
    if serviceData.is_authenticated(): authenticated = "yes"
    else: authenticated = "no"
    print "AUTHENTICATED: %s" % authenticated
    
    if serviceData.is_enabled(): enabled = "yes"
    else: enabled = "no"
    print "ENABLED: %s" % enabled
    
    path = serviceData.get_path()
    if path == None or path == "": path = "<None>"
    print "PATH: %s" % path

    name = serviceData.get_name()
    if name == None or name == "": name = "<None>"
    print "NAME: %s" % name
    
    author = serviceData.get_author()
    if author == None or author == "": author = "<None>"
    print "AUTHOR: %s" % author
            
def add_service_interactively():
    """Adds a new service prompting for every field in the command line."""
    security.check_root()
    
    ok = False
    while (not ok):
        id = raw_input("ID: ")
        ok = (id != None and id != "")
        if not ok: print "Data not valid, try again"

    version = raw_input("Version: ")
    if version == "": version = None
    
    serviceTypeId = raw_input("Service type ID: ")
    if serviceTypeId == "": serviceType = None
    else: serviceType = services.ServiceType(serviceTypeId, None)
    
    ok = False
    while (not ok):
        authenticated = raw_input("Authenticated [y/n]: ")
        authenticated = authenticated.lower()
        ok = (authenticated != None and authenticated != "" and (authenticated == "y" or authenticated == "n"))
        if not ok: print "Data not valid, try again"
    if authenticated == "y": authenticated = True
    else: authenticated = False
    
    ok = False
    while (not ok):
        enabled = raw_input("Enabled [y/n]: ")
        enabled = enabled.lower()
        ok = (enabled != None and enabled != "" and (enabled == "y" or enabled == "n"))
        if not ok: print "Data not valid, try again"
    if enabled == "y": enabled = True
    else: enabled = False
        
    ok = False
    while (not ok):
        path = raw_input("Path: ")
        ok = (path != None and path != "")
        if not ok: print "Data not valid, try again"
    
    name = raw_input("Name: ")
    if name == "": name = None
    
    author = raw_input("Author: ")
    if author == "": author = None
    
    service = services.Service(id, version, serviceType, authenticated, enabled, path, name, author)
    services.add_service(service)
    print "Service added successfully"

def add_service(argv):
    """Adds a new service.
    @param argv: Command line input data
    @type argv: C{list}"""
    security.check_root()
    
    id = tools.get_parameter_value(argv, "id")
    if id == None or id == "": raise exceptions.Exception("Service ID not valid or not specified")
    
    version = tools.get_parameter_value(argv, "v")
    
    serviceTypeId = tools.get_parameter_value(argv, "tid")
    if serviceTypeId == None or serviceTypeId == "": serviceType = None
    else: serviceType = services.ServiceType(serviceTypeId, None)
    
    authenticated = tools.get_parameter_value(argv, "a")
    if authenticated == None or authenticated == "":
        raise exceptions.Exception("Authenticated attribute not valid or not specified")
    else:
        if authenticated != "0" and authenticated != "1": raise exceptions.Exception("Authenticated attribute not valid or not specified")
    authenticated = (authenticated == "1")
    
    enabled = tools.get_parameter_value(argv, "e")
    if enabled == None or enabled == "":
        raise exceptions.Exception("Enabled attribute not valid or not specified")
    else:
        if enabled != "0" and enabled != "1": raise exceptions.Exception("Enabled attribute not valid or not specified")
    enabled = (enabled == "1")
    
    path = tools.get_parameter_value(argv, "p")
    if path == None or path == "": raise exceptions.Exception("Service path not valid or not specified")
    
    name = tools.get_parameter_value(argv, "n")
    author = tools.get_parameter_value(argv, "au")
       
    service = services.Service(id, version, serviceType, authenticated, enabled, path, name, author)
    services.add_service(service)
    print "Service added successfully"

def modify_service_interactively():
    """Modifies an existing service prompting for every field in the command line."""
    security.check_root()
    
    ok = False
    while (not ok):
        oldId = raw_input("Old ID: ")
        ok = (oldId != None and oldId != "")
        if not ok: print "Data not valid, try again"

    ok = False
    while (not ok):
        newId = raw_input("New ID: ")
        ok = (newId != None and newId != "")
        if not ok: print "Data not valid, try again"

    version = raw_input("Version: ")
    if version == "": version = None
    
    serviceTypeId = raw_input("Service type ID: ")
    if serviceTypeId == "": serviceType = None
       
    ok = False
    while (not ok):
        path = raw_input("Path: ")
        ok = (path != None and path != "")
        if not ok: print "Data not valid, try again"
    
    name = raw_input("Name: ")
    if name == "": name = None
    
    author = raw_input("Author: ")
    if author == "": author = None
    
    services.modify_service(oldId, newId, version, serviceTypeId, path, name, author)
    print "Serviced modified successfully"

def modify_service(argv):
    """Modifies an existing service.
    @param argv: Command line input data
    @type argv: C{list}"""
    security.check_root()
    
    oldId = tools.get_parameter_value(argv, "oid")
    if oldId == None or oldId == "": raise exceptions.Exception("Service old ID not valid or not specified")
    
    newId = tools.get_parameter_value(argv, "nid")
    if newId == None or newId == "": raise exceptions.Exception("Service new ID not valid or not specified")
    
    version = tools.get_parameter_value(argv, "v")
    
    serviceTypeId = tools.get_parameter_value(argv, "tid")
    if serviceTypeId == None or serviceTypeId == "": serviceType = None
    else: serviceType = services.ServiceType(serviceTypeId, None)
    
    path = tools.get_parameter_value(argv, "p")
    if path == None or path == "": raise exceptions.Exception("Service path not valid or not specified")
    
    name = tools.get_parameter_value(argv, "n")
    author = tools.get_parameter_value(argv, "au")
    
    services.modify_service(oldId, newId, version, serviceTypeId, path, name, author)
    print "Serviced modified successfully"

def authenticate_service(argv):
    """Enables/disables user authentication on an existing service.
    @param argv: Command line input data
    @type argv: C{list}"""
    security.check_root()
    
    serviceId = tools.get_parameter_value(argv, "id")
    if serviceId == None or serviceId == "": raise exceptions.Exception("Service ID not valid or not specified")
    
    authenticated = tools.get_parameter_value(argv, "a")
    if authenticated == None or authenticated == "": raise exceptions.Exception("Authenticating value not valid or not specified")
    
    if authenticated == "0": authenticated = False
    elif authenticated == "1": authenticated = True
    else: raise exceptions.Exception("Authenticating value not valid")
    
    services.authenticate_service(serviceId, authenticated)
    
    if authenticated: print "Service authenticated successfully"
    else: print "Service deauthenticated successfully"

def enable_service(argv):
    """Enables/disables an existing service.
    @param argv: Command line input data
    @type argv: C{list}"""
    security.check_root()
    
    serviceId = tools.get_parameter_value(argv, "id")
    if serviceId == None or serviceId == "": raise exceptions.Exception("Service ID not valid or not specified")
    
    enabled = tools.get_parameter_value(argv, "e")
    if enabled == None or enabled == "": raise exceptions.Exception("Enabling value not valid or not specified")
    
    if enabled == "0": enabled = False
    elif enabled == "1": enabled = True
    else: raise exceptions.Exception("Enabling value not valid")
    
    services.enable_service(serviceId, enabled)
    
    if enabled: print "Service enabled successfully"
    else: print "Service disabled successfully"

def delete_service(id, confirm):
    """Deletes an existing service.
    @param id: Servide ID
    @type id: C{str}
    @param confirm: Determines if UI must prompt the user a confirmation.
    @type confirm: C{bool}"""
    security.check_root()
    
    if confirm:
        ok = False
        while (not ok):
            response = raw_input("Are you sure you want to delete service '%s'? [y/n]: " % id)
            response = response.lower()
            ok = (response != None and response != "" and (response == "y" or response == "n"))
            if not ok: print "Answer not valid"
        if response == "n": 
            exit(0)
            
    services.delete_service(id)
    print "Service deleted successfully"

def run_callable_service(argv):
    """Runs a callable service that does not require user authentication.
    @param argv: Command line input data
    @type argv: C{list}"""
    serviceId = tools.get_parameter_value(argv, "id")
    if serviceId == None or serviceId == "": raise exceptions.Exception("Service ID not valid or not specified")
    
    serviceArgs = tools.get_parameter_value(argv, "args")
    if serviceArgs != None:
        serviceArgs = serviceArgs.replace(" ", "")
        serviceArgs = serviceArgs.split(",")

    print services.run_callable_service(serviceId, serviceArgs)

def run_callable_auth_service(argv, inputPassword):
    """Runs a callable service that requires user authentication.
    @param argv: Command line input data
    @type argv: C{list}
    @param inputPassword: It determines if user password is passed as an input argument. If *false*, then UI prompts the user password.
    @type inputPassword: C{bool}"""
    serviceId = tools.get_parameter_value(argv, "id")
    if serviceId == None or serviceId == "": raise exceptions.Exception("Service ID not valid or not specified")
    
    userId = tools.get_parameter_value(argv, "user")
    if userId == None or userId == "": raise exceptions.Exception("User ID not valid or not specified")
    
    serviceArgs = tools.get_parameter_value(argv, "args")
    if serviceArgs != None:
        serviceArgs = serviceArgs.replace(" ", "")
        serviceArgs = serviceArgs.split(",")
        
    if inputPassword:
        userPassword = tools.get_parameter_value(argv, "passwd")
        if userPassword == None or userPassword == "": raise exceptions.Exception("User password not valid or not specified")
    else:
        ok = False
        while (not ok):
            userPassword = getpass.getpass("User password: ")
            ok = (userPassword != None and userPassword != "")
            if not ok: print "Data not valid, try again"
        
    print services.run_callable_service(serviceId, serviceArgs, userId, userPassword)
    
def run_automatic_service(argv):
    """Runs an automatic service.
    @param argv: Command line input data
    @type argv: C{list}"""
    serviceId = tools.get_parameter_value(argv, "id")
    if serviceId == None or serviceId == "": raise exceptions.Exception("Service ID not valid or not specified")
    
    serviceArgs = tools.get_parameter_value(argv, "args")
    if serviceArgs != None:
        serviceArgs = serviceArgs.replace(" ", "")
        serviceArgs = serviceArgs.split(",")

    print services.run_automatic_service(serviceId, serviceArgs)
